package com.mitlab.dev.draw.mapper;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mitlab.dev.draw.bean.TypeParam;
import com.mitlab.dev.draw.util.ClassUtils;
import com.mitlab.dev.draw.util.Constants;

public class GraphLinksModel{
	public GraphLinksModel(){}
	@JsonProperty(value="class")
	private String clazz = "go.GraphLinksModel";
	private final String linkFromPortIdProperty = "fromPort";
	private final String linkToPortIdProperty = "toPort";
	private List<NodeData> nodeDataArray;
	public static List<LinkData> linkDataArray;
	private List<NodeData> nodeDataChildArray;
	private List<LinkData> linkDataChildArray;
	private  NodeData startNodeData=null;
	private NodeData endNodeData=null;
	public static int countClass=0;
	public static int countMethod=0;
	
	public String getLinkFromPortIdProperty() {
		return linkFromPortIdProperty;
	}

	public String getLinkToPortIdProperty() {
		return linkToPortIdProperty;
	}

	public List<NodeData> getNodeDataArray() {
		if (nodeDataArray == null) {
			nodeDataArray = Collections.emptyList();
		}
		return nodeDataArray;
	}

	public void setNodeDataArray(List<NodeData> nodeDataArray) {
		this.nodeDataArray = nodeDataArray;
	}

	public List<LinkData> getLinkDataArray() {
		if (linkDataArray == null) {
			linkDataArray = Collections.emptyList();
		}
		return linkDataArray;
	}

	public void setLinkDataArray(List<LinkData> linkDataArray) {
		this.linkDataArray = linkDataArray;
	}
	
	public String getClazz() {
		return clazz;
	}

	public void setClazz(String clazz) {
		this.clazz = clazz;
	}

	public String process_bak() {
		List<LinkData> linkDataArray = this.getLinkDataArray();
		StringBuilder rule = new StringBuilder();
		rule.append("package com.mitlab.dev.rule;\n");
		Set<String> imports = new HashSet<String>();
		Map<String, String> srcMapping = new HashMap<String, String>();
		Map<String, String> targetMapping = new HashMap<String, String>();
		int srcIdx = 0;
		int targetIdx = 0;
		for (LinkData linkData : linkDataArray) {
			if (!imports.contains(linkData.getFrom())) {
				imports.add(linkData.getFrom());
				srcMapping.put(linkData.getFrom(), "$S" + (++srcIdx));
			}
			if (!imports.contains(linkData.getTo())) {
				imports.add(linkData.getTo());
				targetMapping.put(linkData.getTo(), "$T" + (++targetIdx));
			}
		}
		for (String importClazz : imports) {
			rule.append("import ").append(importClazz).append(";\n");
		}

		rule.append("rule \"").append(System.nanoTime()).append("\"\n");
		rule.append("when \n");
		Iterator<Map.Entry<String, String>> srcEntries = srcMapping.entrySet().iterator();
		while (srcEntries.hasNext()) {
			Map.Entry<String, String> entry = srcEntries.next();
			rule.append("\t").append(entry.getValue()).append(":").append(entry.getKey()).append("();\n");
		}
		rule.append("then\n");

		Iterator<Map.Entry<String, String>> targetEntries = targetMapping.entrySet().iterator();
		while (targetEntries.hasNext()) {
			Map.Entry<String, String> entry = targetEntries.next();
			rule.append("\t").append(entry.getKey()).append(" ").append(entry.getValue()).append(" = new ").append(entry.getKey()).append("();\n");
		}

		for (LinkData linkData : linkDataArray) {
			String toPort = linkData.getToPort().substring(0, 1).toUpperCase() + linkData.getToPort().substring(1);
			String fromPort = linkData.getFromPort().substring(0, 1).toUpperCase() + linkData.getFromPort().substring(1);
			rule.append("\t").append(targetMapping.get(linkData.getTo()));
			rule.append(".set").append(toPort).append("(").append(srcMapping.get(linkData.getFrom()));
			rule.append(".get").append(fromPort).append("()").append(");\n");
		}
		rule.append("end");
		return rule.toString();
	}
	public String process(){
		//变量名索引
		countClass=0;
		//遍历主NodeData转换为Map
				Map<String,NodeData> nodeDataMap=new HashMap<String,NodeData>();
				for(NodeData nd:nodeDataArray){
					nodeDataMap.put(nd.getKey(), nd);
					if("start".equalsIgnoreCase(nd.getText())){
						startNodeData=nd;
					}else if("end".equalsIgnoreCase(nd.getText())){
						endNodeData=nd;
					}
				}
				//连接线转换为map
				Map<String,LinkData> linkDataMap=new HashMap<String,LinkData>();
				for(LinkData linkData:linkDataArray){
					linkDataMap.put(linkData.getFrom(),linkData);
				}
				
				//附图
				//连接线转换为map
				Map<String,LinkData> linkDataChildMap=new HashMap<String,LinkData>();
				for(LinkData linkData:linkDataChildArray){
					linkDataChildMap.put(linkData.getFrom()+"_"+linkData.getTo(),linkData);
				}
				//生成代码
				String genratorClassName="generateClass";
				String gratorMethodName="process";
				StringBuffer paramsInput=new StringBuffer();
				//设置类名和方法名
				if(startNodeData!=null){
					if(!"".equals(startNodeData.getClassName()))
					genratorClassName=startNodeData.getClassName();
					if("".equals(startNodeData.getMethodName()))
						gratorMethodName=startNodeData.getMethodName();
					if(startNodeData.getResult()!=null&&startNodeData.getResult().size()>0){
						List<TypeParam> nameList=startNodeData.getResult().get(0).getName();
						if(nameList!=null){
							for(TypeParam typePram:nameList){
								paramsInput.append(typePram.getType()+" "+typePram.getName()+" ,");
							}
							if(paramsInput.length()>0)
							paramsInput.deleteCharAt(paramsInput.length()-1);
						}
							
					}
				}
				//设置方法返回类型
				String methodRetrunStr="";
				if(endNodeData!=null){
					if(endNodeData.getInputparams()!=null&&endNodeData.getInputparams().size()>0)
						methodRetrunStr=endNodeData.getInputparams().get(0).getType();
				}
				StringBuffer codeStr=new StringBuffer();
				codeStr.append("package com.mitlab.dev.rule;\n");
				Set<String> classNames = ClassUtils.getClassName(Constants.packageName, true);
				for (String importClazz : classNames) {
					codeStr.append("import ").append(importClazz).append(";\n");
				}
				codeStr.append("public class "+genratorClassName+"{\n\n");
				
				codeStr.append("public "+methodRetrunStr+" "+gratorMethodName+"("+paramsInput.toString()+"){\n");
				//获取起始节点
				getCode(startNodeData,nodeDataMap,codeStr,null);
				codeStr.append("\t return "+methodRetrunStr+" \n");
				codeStr.append("} \n");
				codeStr.append(getMethodStr());
				codeStr.append("}\n\n}");
				return codeStr.toString();
	}

	public static void main(String[] args) throws Exception {/*
		ObjectMapper om = new ObjectMapper();
		GraphLinksModel glm = new GraphLinksModel();
		//主图node
		List<NodeData> nodeDataArray = new ArrayList<NodeData>();
		NodeData s = new NodeData();
		s.setLoc("0 0");
		s.setText("start");
		s.setKey("-1");
		List <MethodResultBean>resultList1=new ArrayList<MethodResultBean>();
		MethodResultBean mb=new MethodResultBean();
		mb.setName("com.tydic.Address");
		mb.setType("com.tydic.Address");
		resultList1.add(mb);
		s.setResult(resultList1);
		nodeDataArray.add(s);
		NodeData n1 = new NodeData();
		n1.setLoc("300 0");
		n1.setText("1");
		n1.setKey("0");
		n1.setClassName("com.tydic.Persion");
		n1.setMethodName("setPersion");
		List <MethodResultBean>resultList2=new ArrayList<MethodResultBean>();
		MethodResultBean mb2=new MethodResultBean();
		mb2.setName("com.tydic.Address");
		mb2.setType("com.tydic.Address");
		resultList1.add(mb2);
		n1.setResult(resultList2);
		nodeDataArray.add(n1);
		NodeData n2 = new NodeData();
		n2.setLoc("300 0");
		n2.setText("2");
		n2.setKey("1");
		n2.setClassName("com.tydic.Address");
		n2.setMethodName("setAddress");
		List <MethodResultBean>resultList3=new ArrayList<MethodResultBean>();
		MethodResultBean mb3=new MethodResultBean();
		mb3.setName("com.tydic.Address");
		mb3.setType("com.tydic.Address");
		resultList1.add(mb3);
		n2.setResult(resultList3);
		nodeDataArray.add(n2);
		
		NodeData e = new NodeData();
		e.setLoc("400 0");
		e.setText("end");
		e.setKey("2");
		e.setClassName("com.tydic.Address");
		e.setMethodName("setAddress");
		List <MethodResultBean>resultList4=new ArrayList<MethodResultBean>();
		MethodResultBean mb4=new MethodResultBean();
		mb4.setName("com.tydic.Address");
		mb4.setType("com.tydic.Address");
		resultList1.add(mb4);
		e.setResult(resultList1);
		nodeDataArray.add(e);
		glm.setNodeDataArray(nodeDataArray);
		//linldata
		List<LinkData> linkDataArray = new ArrayList<LinkData>();
		LinkData ld = new LinkData();
		ld.setFrom(s.getKey());
		ld.setFromPort("B");
		ld.setTo(n1.getKey());
		ld.setToPort("T");
		linkDataArray.add(ld);
		ld = new LinkData();
		ld.setFrom(n1.getKey());
		ld.setFromPort("B");
		ld.setTo(n2.getKey());
		ld.setToPort("T");
		linkDataArray.add(ld);
		ld = new LinkData();
		ld.setFrom(n2.getKey());
		ld.setFromPort("B");
		ld.setTo(e.getKey());
		ld.setToPort("T");
		linkDataArray.add(ld);
		glm.setLinkDataArray(linkDataArray);
		
		//附图node
		List<NodeData> nodeDataChildArray = new ArrayList<NodeData>();
		NodeData nodeDataChild1=new NodeData();
		nodeDataChild1.setKey(s.getKey());
		nodeDataChildArray.add(nodeDataChild1);
		NodeData nodeDataChild2=new NodeData();
		nodeDataChild2.setKey(n1.getKey());
		nodeDataChildArray.add(nodeDataChild2);
		//附图linkDaa
		List<LinkData> linkDataChildArray1 = new ArrayList<LinkData>();
		LinkData l1=new LinkData();
		l1.setFrom(s.getKey());
		l1.setFromPort("username");
		l1.setTo(n1.getKey());
		l1.setToPort("username");
		linkDataChildArray1.add(l1);
		l1=new LinkData();
		l1.setFrom(n1.getKey());
		l1.setFromPort("password");
		l1.setTo(n2.getKey());
		l1.setToPort("username");
		linkDataChildArray1.add(l1);
		
		GraphLinksModel gmodel=new GraphLinksModel();
		gmodel.setNodeDataArray(nodeDataArray);
		gmodel.setLinkDataArray(linkDataArray);
		gmodel.setNodeDataChildArray(nodeDataChildArray);
		gmodel.setLinkDataChildArray(linkDataChildArray1);
		System.out.println(gmodel.process());
		
		
	*/}
	
	/**
	 * 查询node 的Out的连接线
	 * @param linkDataArray
	 * @param key
	 */
	public static List<LinkData> getLindDataByFrom(List<LinkData> linkDataArray,String key){
		List<LinkData> resultArray=new ArrayList<LinkData>();
		for(LinkData ld:linkDataArray){
			if(key.equals(ld.getFrom()))
				resultArray.add(ld);
		}
		return resultArray;
	}
	
	public static  String getMethodStr(){
		StringBuffer sb=new StringBuffer();
		sb.append("\n");
		sb.append("\n");
		sb.append("\n");
		sb.append("public Method getMethod(Class<?> clazz,String methodName){\n");
		sb.append("\tMethod[] methods = clazz.getMethods();\n");
		sb.append("\tjava.lang.reflect.Method invoke = null;\n");
		sb.append("\tfor (Method m: methods) {\n");
		sb.append("\tif (methodName.equals(m.getName())) {\n");
		sb.append("\tinvoke = m;\n");
		sb.append("\tbreak;\n");
		sb.append("\t}\n");
		sb.append("\t}\n");
		sb.append("\treturn invoke;\n");
		sb.append("}\n");
		return sb.toString();
	}
	/**
	 * 查询子图的node 的Out的连接线
	 * @param linkDataArray
	 * @param key
	 */
	public static List<LinkData> getClidrenLindData(List<LinkData> linkDataArray,String key){
		List<LinkData> resultArray=new ArrayList<LinkData>();
		for(LinkData ld:linkDataArray){
			if(key.equals(ld.getFrom()+"_"+ld.getTo()))
				resultArray.add(ld);
		}
		return resultArray;
	}
	/**
	 * 中间程序代码
	 * @param nodeparent
	 * @param nodeLinks
	 * @return
	 */
	public  String getCode(NodeData nodeparent,Map<String,NodeData> nodeDataMap,StringBuffer codeSb,String resultRef){
		//获取连接线
		List<LinkData> nodeLinks=getLindDataByFrom(linkDataArray,nodeparent.getKey());
		for(LinkData lindData:nodeLinks){
			if(nodeLinks.size()>1)
			codeSb.append("if("+lindData.getCondition()+"){\n");
			//类名引用
			String classNameRef="$"+(countClass++);
			String from=lindData.getFrom();//上一节点key
			String to=lindData.getTo();//下一节点
			NodeData nodeDataChild=nodeDataMap.get(to);
			String nodeDataCClassName= nodeDataChild.getClassName();
			String nodeDataCMethodName= nodeDataChild.getMethodName();
			//新建类
			//如果不是第一次开始调用
			if(!(resultRef==null||"".equals(resultRef)))
			codeSb.append("\t").append(nodeDataCClassName+" "+classNameRef+" = new "+nodeDataCClassName+"();\n");
			//mapper
			//获取mapper连接
			List<LinkData> linkDataChildrenList=getClidrenLindData(linkDataChildArray,from+"_"+to);
			for(LinkData lindDataChild:linkDataChildrenList){
				String toPort = lindDataChild.getToPort().substring(0, 1).toUpperCase() + lindDataChild.getToPort().substring(1);
				String fromPort = lindDataChild.getFromPort().substring(0, 1).toUpperCase() + lindDataChild.getFromPort().substring(1);
				if(!(resultRef==null||"".equals(resultRef)))
				codeSb.append("\t").append(classNameRef).append(".set").append(toPort).append("(").append(resultRef+".get"+fromPort+"()").append(")\n");
			}
			//调用方法
			codeSb.append("\t Method $m"+classNameRef+"=getMethod("+nodeDataChild.getClassName()+".instance(),"+nodeDataCMethodName+");\n");
			//方法返回值
			String resultRefName="$"+countClass++;
			String methodResultType=" void ";
			List<MethodResultBean> resultList=nodeDataChild.getResult();
			if(resultList!=null&&resultList.size()>0){
				methodResultType=resultList.get(0).getType();
			}
			
			codeSb.append("\t "+methodResultType+"  "+resultRefName+" = ("+methodResultType+")$m"+classNameRef+".invoke("+nodeDataChild.getClassName()+".class,"+ classNameRef+");\n");
			
			//递归遍历
			getCode(nodeDataChild,nodeDataMap,codeSb,resultRefName);
			if(nodeLinks.size()>1)
			codeSb.append("}\n");
			}
		return codeSb.toString();
	}
	
	/**
	 * 根据节点获取输入参数类型
	 * @param nodeData
	 * @return
	 */
	public static String getNodePramInType(NodeData nodeData){
		String PramInStr="";
		if(nodeData.getInputparams()!=null&&nodeData.getInputparams().size()>0){
			List<MethodResultBean> methR=nodeData.getInputparams();
			MethodResultBean methodBean=methR.get(0);
			PramInStr=methodBean.getType();
		}
		return PramInStr;
		
	}
	public static String mapperJson() {
		ObjectMapper om = new ObjectMapper();
		ByteArrayOutputStream outs = new ByteArrayOutputStream();
		try {
			om.writeValue(outs, om.readValue(com.mitlab.dev.draw.mapper.GraphLinksModel.class.getResourceAsStream("mapper.json"), com.mitlab.dev.draw.mapper.GraphLinksModel.class));
		} catch (Throwable e) {
			e.printStackTrace();
		} finally {
			try {
				outs.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return outs.toString();
	}

	public List<NodeData> getNodeDataChildArray() {
		return nodeDataChildArray;
	}

	public void setNodeDataChildArray(List<NodeData> nodeDataChildArray) {
		this.nodeDataChildArray = nodeDataChildArray;
	}

	public List<LinkData> getLinkDataChildArray() {
		return linkDataChildArray;
	}

	public void setLinkDataChildArray(List<LinkData> linkDataChildArray) {
		this.linkDataChildArray = linkDataChildArray;
	}

	public NodeData getStartNodeData() {
		return startNodeData;
	}

	public void setStartNodeData(NodeData startNodeData) {
		this.startNodeData = startNodeData;
	}

	public NodeData getEndNodeData() {
		return endNodeData;
	}

	public void setEndNodeData(NodeData endNodeData) {
		this.endNodeData = endNodeData;
	}





}
